# -*- coding: utf-8 -*-
# created on 2016/12/22
from sympy import Eq, Symbol, Abs, sympify, solve, S
from mathsolver.functions.base import BaseFunction, BaseEq, BaseSymbolValue, BaseIneqs, new_latex
from mathsolver.functions.hanshu.duicheng import zhouduicheng_dingyishi
from mathsolver.functions.hanshu.helper import check_func, get_randn_from_interval
from mathsolver.functions.hanshu.hengchengli import fangcheng_hengchengli
from mathsolver.functions.hanshu.zhouqi import has_f
from mathsolver.functions.hanshu.zhouqi import is_axplusb_anyb
from mathsolver.functions.sympy_utils import get_all_child
from mathsolver.functions.hanshu.dingyiyu import QiuDingYiYu
from mathsolver.functions.mathematica.mathematicaSolve import MathematicaSolve


def she_duichengzhou(expr):
    """hs075.设出函数对称轴"""
    z = Symbol('z')
    step = "设函数 %s 的对称轴为 x = %s" % (new_latex(expr), z)
    return z, step


class JueDuiZhiHanShuDuiChengZhou(BaseFunction):
    """hs074.求绝对值函数的对称轴"""

    def solver(self, *args):
        func = check_func(args[0])
        expr, var = func.expression, func.var

        # 提取出所有 Abs(a*x+b) 项
        abs_items = get_all_child(expr, lambda x: x.func is Abs)
        coeff_a_b = [is_axplusb_anyb(item.args[0]) for item in abs_items]
        try:
            xn = sorted(-b / a for a, b in coeff_a_b)
        except TypeError:
            # 如果含有符号，无法排序，raise TypeError
            xn = [-b / a for a, b in coeff_a_b]
        res = (xn[0] + xn[-1]) / 2
        # assert all(item1 + item2 == 2 * res for item1, item2 in zip(xn, reversed(xn))), \
        #     'unable to handle %s' % func.printing()

        self.steps.append(["", "绝对值函数 %s 的对称轴为 x = %s" % (func.printing(), res)])
        self.label.add("求绝对值函数的对称轴")
        self.output.append(BaseEq(['x', res]))
        return self


class HanShuDuiChengZhou(BaseFunction):
    """求函数的对称轴"""

    def solver(self, *args):
        func = check_func(args[0])
        expr, var = func.expression, func.var

        # 如果含有 Abs 尝试类型二
        if expr.has(Abs):
            try:
                return JueDuiZhiHanShuDuiChengZhou().solver(func)
            except Exception:
                pass

        # 如果类型二解不出来，或者不含有 Abs，尝试类型三
        # 设出对称轴
        a, step1 = she_duichengzhou(expr)
        # 函数对称轴定义
        res_eq, step2 = zhouduicheng_dingyishi(a)
        eq = res_eq.lhs - res_eq.rhs
        fxs = set(get_all_child(eq, has_f))
        for fx in fxs:
            inner_f = fx.args[0]
            eq = eq.subs(fx, expr.subs(var, inner_f))

        # 方程恒成立
        ans_mapping, step3 = fangcheng_hengchengli(Eq(eq, 0))
        res = ans_mapping.get(a).args[0]
        step4 = "所以 %s 的对称中心为 x = %s" % (func.printing(), res)

        self.steps = [["", step1], ["", step2], ["", step3], ["", step4]]
        self.label.add("求函数的对称轴")
        self.output.append(BaseEq(['x', res]))
        return self


class DuiChengZhouQiuCanC(BaseFunction):
    """函数对称轴求参数 - 方法一：计算对称轴，和题目给定对称轴比较"""

    def solver(self, *args):
        func = check_func(args[0])
        a = sympify(args[1].value[1])

        # 求函数对称轴
        duichengzhou_solver = HanShuDuiChengZhou().solver(func)
        self.steps.extend(duichengzhou_solver.steps)
        duichengzhou = duichengzhou_solver.output[0].value[1]

        # 解方程
        res = solve(duichengzhou - a, dict=True)[0]
        self.steps.append(["", "所以 %s = %s，解得：%s = %s" % (duichengzhou, a, res.keys()[0], res.values()[0])])
        self.output.append(BaseSymbolValue(res))
        self.label.add("函数对称轴求参数")
        return self


class DuiChengZhouQiuCanT(BaseFunction):
    """函数对称轴求参数 - 方法二：根据 f(x) = f(2a-x) 代入特殊值"""

    def solver(self, *args):
        func = check_func(args[0])
        expr, var = func.expression, func.var
        a = sympify(args[1].value[1])

        relation, step = zhouduicheng_dingyishi(a)
        self.steps.append(["", "根据对称轴定义知：%s" % step])

        try:
            dingyiyu = QiuDingYiYu().solver(func)
        except Exception:
            dingyiyu = S.Reals

        eqs = []
        xs = get_randn_from_interval(dingyiyu, 4)
        for x in xs:
            eqs.append([expr.subs(var, x), expr.subs(var, 2 * a - x)])

        m_output = MathematicaSolve().solver(BaseIneqs(eqs)).output
        result = m_output[0]

        self.steps.append(["", "解得：%s" % result.printing()])
        self.output = m_output
        self.label.add("函数对称轴求参数")
        return self


class DuiChengZhouQiuCan(BaseFunction):
    """函数对称轴求参数 """

    def solver(self, *args):
        for cls in [DuiChengZhouQiuCanC, DuiChengZhouQiuCanT]:
            try:
                return cls().solver(*args)
            except Exception:
                continue
        raise RuntimeError("无法解决该问题")


if __name__ == '__main__':
    pass
